// sdf.c

#include "sdf.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/sm3.h>
#include <gmssl/sm2.h> 

// --- 内部状态和宏定义 ---
#define MOCK_HANDLE ((HANDLE)0xDEADBEEF)

// SDR 错误码 (来自 sdf.h 的定义)
#define SDR_OK          0x00000000
#define SDR_COMMFAIL    SDR_BASE + 0x00000003
#define SDR_ALGNOTSUPPORT SDR_BASE + 0x00000009
#define SDR_STEPERR     SDR_BASE + 0x00000010
#define SDR_INARGERR    SDR_BASE + 0x0000001D
#define SDR_OUTARGERR   SDR_BASE + 0x0000001E

#define SM3_DIGEST_LENGTH 32 
#define SGD_SM3 0x00000004   

// 模拟哈希上下文和状态
static SM3_CTX hash_context;
static int is_hashing = 0;
static int is_device_open = 0;

// ------------------------------------------------------------------
// --- 辅助函数：将 SDF ECCrefPublicKey 结构体转换为 GMSSL 公钥点数组 ---
// ------------------------------------------------------------------

/**
 * 将 SDF ECCrefPublicKey 结构体转换为 GMSSL 期望的 65 字节未压缩公钥点数组 (0x04 || X || Y)。
 */
static LONG sdf_pubkey_to_sm2_point(const ECCrefPublicKey *sdf_pubkey, uint8_t pub_point[65]) {
    if (sdf_pubkey->bits != 256) return SDR_ALGNOTSUPPORT; 
    
    size_t coord_len = 32;

    pub_point[0] = 0x04; // 未压缩点标识符
    memcpy(pub_point + 1, sdf_pubkey->x, coord_len);
    memcpy(pub_point + 1 + coord_len, sdf_pubkey->y, coord_len);
    
    return SDR_OK;
}

// ------------------------------------------------------------------
// --- 设备管理模拟 ---
// ------------------------------------------------------------------

LONG SDF_OpenDevice(HANDLE * phDeviceHandle) { 
    if (is_device_open) return SDR_COMMFAIL;
    *phDeviceHandle = MOCK_HANDLE; 
    is_device_open = 1; 
    return SDR_OK; 
}

LONG SDF_CloseDevice(HANDLE hDeviceHandle) { 
    if (hDeviceHandle != MOCK_HANDLE || !is_device_open) return SDR_COMMFAIL;
    is_device_open = 0; 
    return SDR_OK; 
}

LONG SDF_GetDeviceInfo(HANDLE hSessionHandle, DEVICEINFO *pstDeviceInfo) {
    if (hSessionHandle != MOCK_HANDLE || !is_device_open) return SDR_COMMFAIL;
    memset(pstDeviceInfo, 0, sizeof(DEVICEINFO));
    strcpy(pstDeviceInfo->DeviceName, "GMSSL_SDF_MOCK");
    pstDeviceInfo->HashAlgAbility = SGD_SM3;
    return SDR_OK;
}

// ------------------------------------------------------------------
// --- SM3 接口封装 ---
// ------------------------------------------------------------------

// 6.6.5 SDF_HashInit
LONG SDF_HashInit(HANDLE hSessionHandle, ULONG uiAlgID, ECCrefPublicKey *pucPublicKey, BYTE *pucID, ULONG uiIDLength) {
    if (hSessionHandle != MOCK_HANDLE || !is_device_open) return SDR_COMMFAIL;
    if (uiAlgID != SGD_SM3) return SDR_ALGNOTSUPPORT;
    if (is_hashing) return SDR_STEPERR;

    // 总是先初始化 SM3 上下文
    sm3_init(&hash_context); 
    
    // 判断是否需要 SM2 预处理 (Z_A 计算)
    if (pucPublicKey != NULL && uiIDLength != 0) {
        // --- 情况 1: 需要 SM2 预处理 ---
        
        // 1. 转换公钥为 GMSSL 期望的格式 (65字节数组)
        uint8_t pub_point[65];
        if (sdf_pubkey_to_sm2_point(pucPublicKey, pub_point) != SDR_OK) return SDR_INARGERR;

        BYTE Z_A[32]; // Z_A 存储区

        // 2. 调用确定的 GMSSL 函数 sm2_compute_z 计算 Z_A
        // SM2_Z256_POINT 在头文件里应该是指向 65字节数组的指针
        if (sm2_compute_z(Z_A, (const SM2_Z256_POINT *)pub_point, (const char *)pucID, uiIDLength) != 1) {
            return SDR_ALGNOTSUPPORT; 
        }

        // 3. 将计算出的 Z_A (32字节) 喂给 SM3 上下文
        sm3_update(&hash_context, Z_A, 32);
        
    } else if (pucPublicKey == NULL && uiIDLength == 0) {
        // --- 情况 2: 纯 SM3 杂凑 (sm3_init 已完成) ---
        // 无需额外操作
    } else {
        // 参数不一致检查 (例如，有公钥但无 ID)
        return SDR_INARGERR;
    }

    is_hashing = 1;
    return SDR_OK;
}


// 6.6.6 SDF_HashUpdate
LONG SDF_HashUpdate(HANDLE hSessionHandle, BYTE *pucData, ULONG uiDataLength) {
    if (hSessionHandle != MOCK_HANDLE || !is_device_open) return SDR_COMMFAIL;
    if (!is_hashing) return SDR_STEPERR;
    if (pucData == NULL && uiDataLength != 0) return SDR_INARGERR;
    
    if (uiDataLength > 0) {
        sm3_update(&hash_context, pucData, uiDataLength);
    }
    return SDR_OK;
}


// 6.6.7 SDF_HashFinal
LONG SDF_HashFinal(HANDLE hSessionHandle, BYTE *pucHash, ULONG *puiHashLength) {
    if (hSessionHandle != MOCK_HANDLE || !is_device_open) return SDR_COMMFAIL;
    if (!is_hashing) return SDR_STEPERR;
    if (pucHash == NULL || puiHashLength == NULL) return SDR_OUTARGERR;
    
    // 使用 sm3_finish 结束哈希
    sm3_finish(&hash_context, pucHash);    
    *puiHashLength = SM3_DIGEST_LENGTH;
    is_hashing = 0;
    return SDR_OK;
}
